package com.power.sifa.supervise.executor.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.aventrix.jnanoid.jnanoid.NanoIdUtils;
import com.plf.common.domain.ResponseDTO;
import com.plf.common.domain.YesNo;
import com.plf.common.utils.PdfConvertUtil;
import com.plf.common.utils.WordUtil;
import com.plf.core.base.model.Ha_attachment;
import com.plf.core.base.service.Ha_attachmentService;
import com.power.flowable.api.IPersonalFeign;
import com.power.sifa.approve.model.Apl_admre_audit;
import com.power.sifa.approve.model.Apl_main;
import com.power.sifa.approve.model.Apl_target;
import com.power.sifa.approve.model.Aprv_process_materials;
import com.power.sifa.approve.model.enumeration.St_apply;
import com.power.sifa.approve.model.enumeration.Tp_procmaterial;
import com.power.sifa.approve.model.enumeration.Tp_procmaterialEnum;
import com.power.sifa.approve.model.enumeration.Tp_proctype;
import com.power.sifa.approve.service.*;
import com.power.sifa.approve.thread.ThreadPoolUtil;
import com.power.sifa.base.model.enumeration.Tp_noticemsg;
import com.power.sifa.net.service.ApplyService;
import com.power.sifa.supervise.model.Apl_supervise;
import com.power.sifa.supervise.service.Apl_superviseService;
import com.power.sifa.supervise.service.BusinessSuperviseService;
import com.power.sifa.util.executor.AbstractPostExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
public class SuperviseDecisionCheck extends AbstractPostExecutor {

    // 用户id
    private String userid;
    // 环节分类标识
    private String category;
    // 用户名
    private String username;
    // 单位id
    private String sectionid;
    // 单位名称
    private String sectionname;
    // 部门id
    private String deptid;
    // 部门名称
    private String deptname;
    // 处理意见
    private String remark;
    // 行政区划
    private String adid;
    // 环节名称
    private String taskname;

    @Resource
    private Apl_superviseService apl_superviseService;
    @Resource
    private Apl_admre_auditService apl_admre_auditService;
    @Resource
    private Apl_targetService apl_targetService;
    @Resource
    private Apl_applicantService apl_applicantService;

    @Resource
    private IPersonalFeign iPersonalFeign;

    @Resource
    private Apl_mainService apl_mainService;

    @Resource
    private BusinessApproveService businessApproveService;

    @Resource
    private ApplyService applyService;

    @Resource
    private Aprv_process_materialsService aprv_process_materialsService;

    @Resource
    private Ha_attachmentService ha_attachmentService;

    @Resource
    private BusinessSuperviseService businessSuperviseService;

    @Resource
    private Apl_arrive_detailService apl_arrive_detailService;

    @Resource
    private Apl_dossierService apl_dossierService;

    @Resource
    private Apl_archiveService apl_archiveService;

    @Override
    public void init(Map<String, Object> initdata) {
        this.userid = (String) initdata.get("userid");
        this.category = (String) initdata.get("category");
        this.username = (String) initdata.get("username");
        this.sectionid = (String) initdata.get("sectionid");
        this.sectionname = (String) initdata.get("sectionname");
        this.deptid = (String) initdata.get("deptid");
        this.deptname = (String) initdata.get("deptname");
        this.remark = (String) initdata.get("remark");
        this.adid = (String) initdata.get("adid");
        this.taskname = (String) initdata.get("taskname");
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> execute() throws Exception {
        // 1、生成审批表
        Apl_admre_audit auditObj = this.createSuperviseDecision(super.applyid, this.userid, this.username, Tp_proctype.SUPERVISE_DECISION);
        Apl_supervise supObj = this.apl_superviseService.getById(auditObj.getApplyid());
        Apl_main mainObj = this.apl_mainService.getById(super.applyid);
        Apl_main faMainObj = this.apl_mainService.getById(auditObj.getApplyid());

        if(null == supObj.getDecisiontype()) {
            log.error("SuperviseDecisionCheck 复议监督决定类型不能为空");
            throw new RuntimeException("复议监督决定类型不能为空");
        }

        // 2、新增对应的办结时限天数 && 删除子流程状态
        if (supObj.getIsrectifica().equals(YesNo.YES)) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(new Date());
            cal.add(Calendar.DATE, 60);
            Date endTIme = cal.getTime();
            SimpleDateFormat formatT = new SimpleDateFormat("yyyy年M月d日");
            supObj.setEnddate(formatT.format(endTIme));
            supObj.setSonstatus(null);

        }
        // 3、关闭子流程
        ResponseDTO res = this.iPersonalFeign.terminationSonProcess(faMainObj.getInstid(), mainObj.getInstid(), this.userid, "申请已决定，故中途办结");
        if (0 != res.getCode()) {
            log.error("SuperviseDecisionCheck 关闭所有在办子流程失败 ->  msg[{}]", res.getMsg());
            throw new RuntimeException("关闭所有在办子流程失败");
        }

        // 4、激活主流程 并且走到下一步
        // 5先激活 (没挂起就拿一个taskid)
        ResponseDTO activeRes = this.iPersonalFeign.activationProcess(faMainObj.getInstid());
        if(0 != activeRes.getCode()) {
            log.error("SuperviseDecisionCheck 激活父流程失败 -> msg[{}]", activeRes.getMsg());
            throw new RuntimeException("SuperviseDecisionCheck 激活父流程失败 -> " + activeRes.getMsg());
        }
        // 5.1 父流程自动走一步
        String taskid = (String) activeRes.getData(); // 父流程任务id
        Map<String,Object> variabeMap = new HashMap<>();
        variabeMap.put("IsRectify", supObj.getIsrectifica());
        variabeMap.put("userid", userid);
        ResponseDTO axecRes =  this.iPersonalFeign.processNext(faMainObj.getFormid(), faMainObj.getId(), taskid, userid, variabeMap);
        if(0 != axecRes.getCode()) {
            log.error("SuperviseDecisionCheck 完成父流程任务失败 -> msg[{}]", axecRes.getMsg());
            throw new RuntimeException("SuperviseDecisionCheck 完成父流程任务失败");
        }
        // 5.2 保存主流程的流程状态为已办结
        if (supObj.getIsrectifica().equals(YesNo.NO)) {
            faMainObj.setStatus(St_apply.FINISH);
            this.apl_mainService.saveOrUpdate(faMainObj);
        }

        // 5、文书盖章
        this.businessApproveService.templateStamp(auditObj.getApplyid(), Tp_proctype.SUPERVISE_DECISION);

        ThreadPoolUtil.executor.execute(() -> {
            this.apl_archiveService.initialSuperviseArchiveData(auditObj.getApplyid());
            // 5.1 初始化归档电子卷宗数据
            this.apl_dossierService.buildInitSuperviseDossier(auditObj.getApplyid());
        });

        // 6、发送赣政通代办通知及被申请人通知消息
        // 查询被申请人
//        try {
//            this.businessSuperviseService.sendApplicantMessage(auditObj.getApplyid(), this.userid);
//        } catch (Exception e) {
//            log.error("SuperviseDecisionCheck 发送被申请人短信通知失败 -> msg[{}]", e.getMessage());
//        }
        this.apl_arrive_detailService.createSaveNotice(faMainObj.getId(), faMainObj.getAcceptcode(), userid,
                7, faMainObj.getAcceptcode() + "已审批通过，请及时送达《行政复议监督告知书》", Tp_procmaterial.SUPERVISE_TELL, Tp_noticemsg.SUPERVISE_ARRIVE);

        List<Apl_target> targetList = apl_targetService.getTargetListByApplyid(auditObj.getApplyid());
        if (CollUtil.isNotEmpty(targetList)) {
            List<String> phones = targetList.stream().map(Apl_target::getPhone).filter(ObjectUtil::isNotEmpty)
                    .distinct().collect(Collectors.toList());
            // 发送赣政通代办和短信通知 （短信通知暂时不需要）
            this.businessSuperviseService.sendDiTodo(auditObj.getApplyid(), this.userid, phones, Boolean.TRUE);
        }
        return null;
    }



    public Apl_admre_audit createSuperviseDecision(String applyid, String userid, String username, Integer type) throws Exception {
        // 1. 查询子流程的表单数据
        Apl_main mainObj = this.apl_mainService.getById(applyid);
        Apl_admre_audit auditObj = this.apl_admre_auditService.getById(applyid);
        Map<String, Object> formData = this.applyService.formLoadField(mainObj.getFormid(), applyid);
        Apl_supervise supObj = this.apl_superviseService.getById(auditObj.getApplyid());
        formData.put("apl_admreview_hearsecondname", supObj.getSecondname());
        super.ApprovalField(formData);
        // 2. 生成并上传文件
        Ha_attachment attachment;
        byte[] pdfByte;
        WordUtil wordUtil = new WordUtil("SuperviseDecisionCheck.docx");
        wordUtil.replaceTable(formData);
        try (OutputStream os = wordUtil.createWord();
             InputStream is = new ByteArrayInputStream(((ByteArrayOutputStream) os).toByteArray())) {
            pdfByte = PdfConvertUtil.word2pdfWithFont(is);
            attachment = ha_attachmentService.upload(new ByteArrayInputStream(pdfByte), "行政复议监督案件审批表.pdf");
            log.info("createSuperviseDecision 三级审批文书生成并保存成功 -> {}", attachment.getId());
        } catch (Exception e) {
            log.error("createSuperviseDecision 三级审批文书生成并保存失败 ->  msg[{}]", e.getMessage());
            throw new RuntimeException("createSuperviseDecision 三级审批文书生成并保存失败 -> " + e.getMessage());
        }

        // 2. 保存审批系统文书, 只存父流程
        Aprv_process_materials docObj = new Aprv_process_materials(Tp_procmaterialEnum.ADMRE_REPORT);
        docObj.setId(applyid + NanoIdUtils.randomNanoId());
        // 通知书类型枚举
        docObj.setMattype(Tp_procmaterial.ADMRE_REPORT);
        docObj.setAttachid(attachment.getId());
        docObj.setCreateuserid(userid);
        docObj.setCreateuser(username);
        docObj.setCreatetime(new Date());
        docObj.setApplyid(auditObj.getApplyid());
        docObj.setType(type);
        this.aprv_process_materialsService.saveOrUpdate(docObj);

        return auditObj;

    }

}
